
# python imports
import os, logging

# google appengine API imports
from google.appengine.ext import db
from google.appengine.api import memcache
from google.appengine.datastore import entity_pb
from google.appengine.ext.webapp import template

# local imports
import statestore

class InternalError(Exception):
	pass

class Block(db.Model):
	state = db.IntegerProperty()
	name = db.StringProperty()
	value = db.BlobProperty()

class BlockStore:
	# constructor
	def __init__(self,key,max_entities=10):
		self.key = key
		self.max_entities = max_entities
		self.state = statestore.StateStore("state" + self.key,max_entities=max_entities)
	def _memcache_get(self,name):
		return memcache.get(self.key + "-" + name)
	def _memcache_set(self,name,value):
		if not memcache.add(self.key + "-" + name,value):
			logging.error("Unable to add to memcache for '%s'" % name)
	def _memcache_delete(self,name):
		logging.debug("Deleting memcache for '%s'" % name)
		if not memcache.delete(self.key + "-" + name):
			logging.error("Unable to delete from memcache for '%s'" % name)
	def _block_fetch(self,name,state):
		# get HTML from storage
		q = Block.all()
		q.filter("name =", name)
		q.filter("state =", state)
		for block in q.fetch(1):
			return block
		return None
	def _state_fetch(self,name):
		# get state for this name, or default to 1
		state = self.state[name]
		if state==None:
			state = 1
		return int(state)
	def __getitem__(self,name):
		assert isinstance(name,basestring)
		# get HTML from memcache
		block_html = self._memcache_get(name)
		if block_html:
			logging.debug("Got block from memcache, '%s'" % name)
			return block_html
		# get HTML from storage
		block = self._block_fetch(name,self._state_fetch(name))
		if block:
			logging.debug("Fetched block '%s' from storage, saving to memcache" % name)
			self._memcache_set(name,block.value)
			return block.value
		else:
			logging.debug("Block '%s' not found in storage or memcache, returning None" % name)
			return None
	@property
	def blocks(self):
		blocks = { }
		# fetch block names
		q = Block.all()
		for block in q:
			if blocks.get(block.name)==None:
				blocks[block.name] = { }
			if blocks[block.name].get(block.state)==None:
				blocks[block.name][block.state] = block.value
		return blocks
	def block_iterate(self,name,state):
		while True:
			block = self._block_fetch(name,state)
			if block:
				yield block
			else:
				break
	def setstate(self,name,value):
		self.state[name] = value
		self._memcache_delete(name)
	def getblock(self,name,state):
		block = self._block_fetch(name,state)
		if block:
			return block.value
		else:
			return None
	def setblock(self,name,state,value):
		block = self._block_fetch(name,state)
		if not block:
			block = Block()
			block.name = name
			block.state = int(state)
			block.value = value
		else:
			block.value = value
		block.put()
		# clear out the memcache
		self._memcache_delete(name)
	def reset(self):
		# remove all blocks and memcache
		q = Block.all()
		for block in q:
			block.delete()
			self._memcache_delete(block.name)
		# remove state
		self.state.reset()
		# flush out the memcache
		if not memcache.flush_all():
			logging.error("Unable to flush the cache")
	def fromfile(self,name,path):
		state = self._state_fetch(name)
		# remove existing blocks
		for block in self.block_iterate(name,state):
			block.delete()
		# add in the new block
		block = Block()
		block.name = name
		block.state = int(state)
		block.value = template.render(path,{ })
		block.put()
		# set the state
		self.state[name] = state
		# clear out the memcache
		self._memcache_delete(name)
		# return the block
		logging.debug("Returning HTML = %s" % block.value)
		return block.value
